package top.ieei.demo.dhcp;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;


public class DHCPServlet
{
  private static final Logger logger = Logger.getLogger(DHCPServlet.class.getName().toLowerCase());

  protected DHCPCoreServer server = null;

  public void init(Properties props)
  {
  }

  public DatagramPacket serviceDatagram(DatagramPacket requestDatagram)
  {
    if (requestDatagram == null) return null;

    try
    {
      DHCPPacket request = DHCPPacket.getPacket(requestDatagram);

      if (request == null) return null;

      if (logger.isLoggable(Level.FINER)) {
        logger.finer(request.toString());
      }

      DHCPPacket response = service(request);

      if (logger.isLoggable(Level.FINER)) {
        logger.finer("service() done");
      }
      if (response == null) return null;

      InetAddress address = response.getAddress();
      if (address == null) {
        logger.warning("Address needed in response");
        return null;
      }
      int port = response.getPort();

      byte[] responseBuf = response.serialize();

      if (logger.isLoggable(Level.FINER)) logger.finer("Buffer is " + responseBuf.length + " bytes long");

      DatagramPacket responseDatagram = new DatagramPacket(responseBuf, responseBuf.length, address, port);
      if (logger.isLoggable(Level.FINER)) {
        logger.finer("Sending back to" + address.getHostAddress() + '(' + port + ')');
      }
      postProcess(requestDatagram, responseDatagram);
      return responseDatagram;
    } catch (DHCPBadPacketException e) {
      logger.log(Level.INFO, "Invalid DHCP packet received", e);
    } catch (Exception e) {
      logger.log(Level.INFO, "Unexpected Exception", e);
    }

    return null;
  }

  protected DHCPPacket service(DHCPPacket request)
  {
    if (request == null) {
      return null;
    }

    if (!request.isDhcp()) {
      logger.info("BOOTP packet rejected");
      return null;
    }

    Byte dhcpMessageType = request.getDHCPMessageType();

    if (dhcpMessageType == null) {
      logger.info("no DHCP message type");
      return null;
    }

    if (request.getOp() == 1) {
      switch (dhcpMessageType.byteValue()) { case 1:
        return doDiscover(request);
      case 3:
        return doRequest(request);
      case 8:
        return doInform(request);
      case 4:
        return doDecline(request);
      case 7:
        return doRelease(request);
      case 2:
      case 5:
      case 6: } logger.info("Unsupported message type " + dhcpMessageType);
      return null;
    }
    if (request.getOp() == 2)
    {
      logger.info("BOOTREPLY received from client");
      return null;
    }
    logger.warning("Unknown Op: " + request.getOp());
    return null;
  }

  protected DHCPPacket doDiscover(DHCPPacket request)
  {
    logger.fine("DISCOVER packet received");
    return null;
  }

  protected DHCPPacket doRequest(DHCPPacket request)
  {
    logger.fine("REQUEST packet received");
    return null;
  }

  protected DHCPPacket doInform(DHCPPacket request)
  {
    logger.fine("INFORM packet received");
    return null;
  }

  protected DHCPPacket doDecline(DHCPPacket request)
  {
    logger.fine("DECLINE packet received");
    return null;
  }

  protected DHCPPacket doRelease(DHCPPacket request)
  {
    logger.fine("RELEASE packet received");
    return null;
  }

  protected void postProcess(DatagramPacket requestDatagram, DatagramPacket responseDatagram)
  {
  }

  public DHCPCoreServer getServer()
  {
    return this.server;
  }

  public void setServer(DHCPCoreServer server)
  {
    this.server = server;
  }
}
